#!/usr/bin/env python

import cPickle
import optparse
import os
import sys

import batchcat
import charmicat

def main():
    '''
    bcat_filter.py [opts] file.h5 [file.h5 [...]]

    Apply filters from a module supplied from the command line or inferred from the file via
    batch queue submission.
    '''

    op = optparse.OptionParser(usage=main.__doc__)

    op.add_option("-c", "--cutset", dest="cutsets", action='append', default=[],
                  help="Apply cutset NAME (can be used more than once)")
    op.add_option("-f", "--force", dest="force", default=False, action='store_true',
                  help="Force overwrite of output directory")
    op.add_option("-m", "--module", dest='module_name', default=None, 
                  help="Use module MODULE instead of inferring from input", metavar='MODULE')
    op.add_option("-n", "--njobs", dest='njobs', type='int', default=100, 
                  help="Divide input among N simultaneous jobs", metavar='N')
    op.add_option("-r", "--replace", action="append", dest="replace", default=[], nargs=2,
                  help="Replace in cutset cut named CUT1 with cut named CUT2")
    op.add_option("-s", dest="list", action='append', default=[],
                  help="Apply the cut NAME (can be used more than once)")
    op.add_option("-x", dest='exclude', action='append', default=[],
                  help="Exclude cut NAME (can be repeated)", metavar='NAME')
    op.add_option("-z", dest='complevel', type='int', default=1,
                  help="Set output compression level 0-9", metavar='0-9')
    op.add_option("--start-on", dest="start_on", default=None,
                  help="Apply only cuts downstream (inclusive) of NAME", metavar='NAME')

    batchcat.add_options(op)

    op.get_option('--bcat-duration').default = '04:00:00'

    opts, args = op.parse_args()

    if len(args) == 0:
        msg = "Please supply at least one input file."
        raise charmicat.BadCommandLineError(msg, -1)

    if not opts.module_name:
        opts.module_name = charmicat.module_name_from_paths(args)
    
    try:
        module = __import__(opts.module_name)           
    except ImportError:
        msg = "Error importing module `{0}'".format(opts.module_name)
        raise charmicat.BadCommandLineError(msg, -2)

    cut_list = charmicat.build_cut_list(module, opts)

    origdir = os.getcwd()

    if opts.bcat_outdir:
        rootdir = os.path.abspath(charmicat.safe_mkdir(opts.bcat_outdir, force=opts.force, force_opt='-f'))
    elif opts.cutsets:
        rootdir = os.path.abspath(charmicat.safe_mkdir('+'.join(opts.cutsets), force=opts.force, force_opt='-f'))
    else:
        rootdir = os.path.abspath(os.getcwd())

    args = [os.path.abspath(arg) for arg in args]

    args.sort()
    if len(args) < opts.njobs:
        opts.njobs = len(args)

    cutdir = rootdir
    for c in cut_list:
        cutdir = charmicat.safe_mkdir(os.path.join(cutdir, c.name), force=opts.force, force_opt='-f')
        
        os.chdir(cutdir)
        
        c.prepare(cutdir, opts)

        link_path = os.path.join(rootdir, c.name)
        
        if not os.access(link_path, os.F_OK):
            os.symlink(os.getcwd(), os.path.join(rootdir, c.name))

        if not os.access('./top', os.F_OK):
            os.symlink(rootdir, './top')                

    os.chdir(rootdir)
     
    rm = batchcat.resource_managers['default']
    
    for i, pathtup in enumerate(charmicat.n_groups(opts.njobs, args)):
        pklpath = os.path.join(rootdir, 'job_{0}_paths.pkl'.format(i))
        with open(pklpath, 'w') as fp:
            cPickle.dump(pathtup, fp)

        command_line = 'python -m batchcat.run.filter {0} {1} {2} {3}'
        command_line = command_line.format(opts.module_name, 
                                           os.path.abspath(pklpath), 
                                           rootdir,
                                           ' '.join([c.name for c in cut_list]))
                                
        rm.add_job('bcat_filter' + str(i),
                   command_line, 
                   opts)
        
    if opts.bcat_write is None:
        rm.submit()
    else:
        rm.write(path=opts.bcat_write)
    
        

    return 0


if __name__ == "__main__":
    try:
        sys.exit(main())
    except charmicat.BadCommandLineError, e:
        import os
        sys.stderr.write(str(e) + "\n")
        sys.stderr.write("See `{0} -h' for more.\n".format(os.path.basename(sys.argv[0])))
        sys.stderr.flush()
        sys.exit(e.retcode)

